package com.spica.spicaschool.component.spicatextview

import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.util.AttributeSet
import android.view.animation.AccelerateInterpolator
import android.widget.TextView
import androidx.appcompat.widget.AppCompatEditText
import com.spica.spicaschool.R


/**
 * 实现了光标闪烁和渐隐的TextView
 */
class SpicaEditText : AppCompatEditText {

    /**
     * 当前的透明度
     */
    private var cursorAlpha = 0
        set(value) {
            field = value
            invalidate()
        }
    private val cursorPaint = Paint(Paint.ANTI_ALIAS_FLAG)


    /**
     * 动画对象
     */
    private val breatheAnimator = ObjectAnimator.ofInt(this, "cursorAlpha", 0, 255).apply {
        duration = BREATHE_DURATION
        repeatMode = ValueAnimator.REVERSE
        repeatCount = ValueAnimator.INFINITE
        interpolator = AccelerateInterpolator()
    }

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    init {
        cursorPaint.color = context.getColor(R.color.colorDarkText)
        cursorDrawable = GradientDrawable()
        cursorDrawable.apply {
            val round = context.dp(8)
            cornerRadii = floatArrayOf(
                round, round,
                round, round,
                round, round,
                round, round
            )
            setColor(Color.TRANSPARENT)
        }
        setCompatCursorDrawable(cursorDrawable)
        breatheAnimator.start()

    }


    /**
     * 光标对象
     */
    private var cursorDrawable: GradientDrawable


    override fun onSelectionChanged(selStart: Int, selEnd: Int) {

        super.onSelectionChanged(selStart, selEnd)

    }

    override fun onDraw(canvas: Canvas?) {
        if (isFocused && breatheAnimator.isRunning) {
            val horizontalPadding = compoundPaddingLeft
            val verticalPadding = extendedPaddingTop + getVerticalOffsetByHook(true)
            val bounds = cursorDrawable.bounds
            paint.alpha = cursorAlpha


            canvas?.drawRoundRect(
                bounds.left + horizontalPadding.toFloat(),
                bounds.top + verticalPadding.toFloat(),
                bounds.right + horizontalPadding.toFloat(),
                bounds.bottom + verticalPadding.toFloat(),
                8F, 8F,
                paint
            )
        }


        super.onDraw(canvas)

    }


    /**
     * 设置光标
     */
    private fun setCompatCursorDrawable(gradientDrawable: GradientDrawable) {
        gradientDrawable.setSize(8, textSize.toInt())
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            this.textCursorDrawable = gradientDrawable
            return
        }

        try {
            val editorField = try {
                TextView::class.java.getDeclaredField("mEditor").apply { isAccessible = true }
            } catch (t: Throwable) {
                t.printStackTrace()
                null
            }
            val editor = editorField?.get(this) ?: this
            val editorClass: Class<*> =
                if (editorField == null) TextView::class.java else editor.javaClass

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                editorClass
                    .getDeclaredField("mDrawableForCursor")
                    .apply { isAccessible = true }
                    .run { set(editor, gradientDrawable) }
            } else {
                editorClass
                    .getDeclaredField("mCursorDrawable")
                    .apply { isAccessible = true }
                    .run { set(editor, arrayOf(gradientDrawable, gradientDrawable)) }
            }
        } catch (t: Throwable) {
            t.printStackTrace()
        }
    }


    companion object {
        private const val BREATHE_DURATION = 800L
        private const val MOVEING_DURATION = 250L
    }

    private fun getVerticalOffsetByHook(forceNormal: Boolean): Int {
        if (getVerticalOffsetMethod == null) return 0
        return getVerticalOffsetMethod.invoke(this, forceNormal) as Int
    }

    private val getVerticalOffsetMethod = try {
        TextView::class.java.getDeclaredMethod(
            "getVerticalOffset",
            Boolean::class.javaPrimitiveType
        )
            .apply { isAccessible = true }
    } catch (t: Throwable) {
        t.printStackTrace()
        null
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        breatheAnimator.pause()
    }

    override fun onVisibilityAggregated(isVisible: Boolean) {
        super.onVisibilityAggregated(isVisible)
        if (!isVisible) breatheAnimator.pause() else breatheAnimator.resume()
    }


    private fun Context.dp(value: Int): Float = (value * resources.displayMetrics.density)


}